package com.ht.api.service.report;

import java.sql.Struct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import cn.hutool.core.util.StrUtil;
import com.ht.api.db.Db;
import com.ht.api.db.DbConfig;
import com.ht.api.db.DbList;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.ht.api.db.SqlParser;
import com.ht.api.util.RuleSqlUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 报表service
 * @author asq
 * @createTime 2025年4月21日 11:12:04
 */
@Slf4j
public class ReportService {

	/**
	 * 根据报表配置，解析出sql
	 * @param config
	 * @return
	 */
	public static DbList parseConfigSql(DataSource ds, JSONObject config, JSONObject param) {
		JSONObject condition = param.getJSONObject("condition");

		// 查找group字段
		String table = config.getStr("table_code");
		String groupColumnId = config.getStr("group");
		String groupColumn = DbConfig.getColumnCode(table, groupColumnId);

		// 添加group函数
		String groupFunc = config.getStr("group_func");
		if (StrUtil.isNotBlank(groupFunc)) {
			if ("year".equals(groupFunc)) {
				groupColumn = String.format("date_format(%s, '%%Y')", groupColumn);
			} else if ("month".equals(groupFunc)) {
				groupColumn = String.format("date_format(%s, '%%Y-%%m')", groupColumn);
			} else if ("day".equals(groupFunc)) {
				groupColumn = String.format("date_format(%s, '%%Y-%%m-%%d')", groupColumn);
			} else if ("ago".equals(groupFunc)) {
				groupColumn = String.format("IF(datediff(curdate(), %s) <= 30,datediff(curdate(), %s),ROUND(datediff(curdate(), %s) / 10) * 10)", groupColumn,groupColumn,groupColumn);
			}
		}

		String fun = config.getByPath("func.func", String.class);
		String funFiled = config.getByPath("func.field", String.class);

		if (StrUtil.isBlank(funFiled) || funFiled.equals("1")) {
			fun += "(1)";
		} else {
			String funColumn = DbConfig.getColumnCode(table, funFiled);

			if ("min_ago".equals(fun)) {
				fun = String.format("DATEDIFF(CURRENT_DATE(), MIN(%s))", funColumn);
			} else if ("max_ago".equals(fun)) {
				fun = String.format("DATEDIFF(CURRENT_DATE(), MAX(%s))", funColumn);
			} else {
				fun += "("+funColumn+")";
			}

		}

		String conditionField = config.getStr("condition_field");
		String conditionColumn = DbConfig.getColumnCode(table, conditionField);

		SqlParser sqlParser = param.toBean(SqlParser.class).setTable(table);
		sqlParser.select(groupColumn + " " + DbConfig.getColumnCode(table, groupColumnId) +  ", " + fun + " num");
		sqlParser.group(groupColumn);

		List<Object> conditionParams = new ArrayList<>();
		String conditionSql = RuleSqlUtil.buildConditionSql(condition, conditionParams);
//		sqlParser.subwhere(conditionColumn, "in", conditionSql);

		String sql = sqlParser.getSql();

		sqlParser.getParamList().addAll(conditionParams);

		if (!config.isNull("nesting") && config.getBool("nesting")) {
			sql = "select num group_value, count(1) num from (" + sql + ") t group by num";
		}

		log.info(sql.toString());

		DbList list = Db.query(ds, sql, sqlParser.getParamList());

		return list;
	}
	
	/**
	 * 替换sql中的变量
	 * @param ds 数据源
	 * @param sql sql语句
	 * @param body 前端参数
	 * @return
	 */
	public static String filterSql(DataSource ds, String sql, JSONObject body) {
		// 根据前端参数处理sql并执行
		sql = replaceParam(sql, body);// 替换前端参数
		sql = filterParam(sql, body);// 去掉前端未传的参数语句
		return sql;
	}

	/**
	 * 将sql语句中的{}替换为前端参数值
	 * @param sql
	 * @param body
	 * @return
	 */
	private static String replaceParam(String sql, JSONObject body) {
		JSONArray paramArr = body.getJSONArray("where");
		if (paramArr == null || paramArr.isEmpty()) {
			return sql;
		}

		// 将参数转为Map方便查找
		Map<String, Object> paramMap = new HashMap<>();
		for (int i = 0; i < paramArr.size(); i++) {
			JSONObject param = paramArr.getJSONObject(i);
			paramMap.put(param.getStr("field"), param.get("value"));
		}

		// 使用正则表达式匹配所有{变量}并直接替换
		Pattern pattern = Pattern.compile("\\{(.+?)\\}");
		Matcher matcher = pattern.matcher(sql);
		StringBuffer sb = new StringBuffer();

		while (matcher.find()) {
			String paramName = matcher.group(1);
			Object paramValue = paramMap.get(paramName);
			// 直接替换为参数值（不区分类型，不做任何处理）
			matcher.appendReplacement(sb, paramValue != null ? paramValue.toString() : matcher.group());
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 将sql语句中的[]过滤掉（如果前端没有传相应值的时候）
	 * @param sql
	 * @param body
	 * @return
	 */
	private static String filterParam(String sql, JSONObject body) {
		JSONArray paramArr = body.getJSONArray("where");
		if (paramArr == null || paramArr.isEmpty()) {
			// 如果没有参数，移除所有中括号内容
			return sql.replaceAll("\\[.*?\\]", "");
		}

		// 收集所有前端传递的参数key
		Map<String, Boolean> paramKeys = new HashMap<>();
		for (int i = 0; i < paramArr.size(); i++) {
			JSONObject param = paramArr.getJSONObject(i);
			paramKeys.put(param.getStr("field"), true);
		}

		// 使用正则表达式匹配所有[条件语句]
		Pattern pattern = Pattern.compile("\\[(.*?)\\]");
		Matcher matcher = pattern.matcher(sql);
		StringBuffer sb = new StringBuffer();

		while (matcher.find()) {
			String condition = matcher.group(1);
			// 检查条件语句中是否包含前端没有传递的参数
			boolean shouldKeep = true;

			// 提取条件语句中的所有参数名
			Pattern paramPattern = Pattern.compile("\\{(.+?)\\}");
			Matcher paramMatcher = paramPattern.matcher(condition);

			while (paramMatcher.find()) {
				String paramName = paramMatcher.group(1);
				if (!paramKeys.containsKey(paramName)) {
					shouldKeep = false;
					break;
				}
			}

			if (shouldKeep) {
				// 保留这个条件语句
				matcher.appendReplacement(sb, condition);
			} else {
				// 移除这个条件语句
				matcher.appendReplacement(sb, "");
			}
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 替换SQL中的ORDER BY子句
	 * @param sql 原始SQL语句
	 * @param orderArray 新的排序字段数组，包含field和sort属性
	 * @return 替换了ORDER BY后的SQL语句
	 */
	public static String appendOrder(String sql, JSONArray orderArray) {
		// 如果排序数组为空，直接返回原SQL(保留原有排序)
		if (orderArray == null || orderArray.isEmpty()) {
			return sql;
		}

		// 查找已有ORDER BY子句的位置
		int orderByIndex = sql.indexOf("order by");

		// 如果没有找到ORDER BY，直接在末尾添加
		if (orderByIndex == -1) {
			return buildNewOrderByClause(sql, orderArray);
		}

		// 找到ORDER BY的位置，截取前面的部分
		String beforeOrderBy = sql.substring(0, orderByIndex);
		// 查找ORDER BY子句结束的位置(分号或语句结束)
		int orderByEnd = findOrderByEnd(sql, orderByIndex);

		// 截取ORDER BY之前的部分 + 新的ORDER BY子句
		return beforeOrderBy + buildNewOrderByClause("", orderArray)
				+ (orderByEnd < sql.length() ? sql.substring(orderByEnd) : "");
	}

	/**
	 * 构建新的ORDER BY子句
	 */
	private static String buildNewOrderByClause(String baseSql, JSONArray orderArray) {
		StringBuilder builder = new StringBuilder(baseSql);
		builder.append(" order by ");

		for (int i = 0; i < orderArray.size(); i++) {
			JSONObject order = orderArray.getJSONObject(i);
			if (i > 0) {
				builder.append(", ");
			}
			builder.append(order.getStr("field"))
					.append(" ")
					.append(order.getStr("sort"));
		}

		return builder.toString();
	}

	/**
	 * 查找ORDER BY子句结束的位置
	 */
	private static int findOrderByEnd(String sql, int orderByStart) {
		// 查找下一个关键字(GROUP BY/LIMIT/WHERE等)或语句结束
		int groupByPos = sql.toLowerCase().indexOf("group by", orderByStart);
		int limitPos = sql.toLowerCase().indexOf("limit", orderByStart);
		int wherePos = sql.toLowerCase().indexOf("where", orderByStart);

		// 找到最近的一个关键字位置
		int minPos = Integer.MAX_VALUE;
		if (groupByPos != -1) minPos = Math.min(minPos, groupByPos);
		if (limitPos != -1) minPos = Math.min(minPos, limitPos);
		if (wherePos != -1) minPos = Math.min(minPos, wherePos);

		// 如果没有找到其他关键字，返回字符串长度
		return minPos != Integer.MAX_VALUE ? minPos : sql.length();
	}

	/**
	 * 添加LIMIT子句到SQL中
	 * @param sql 原始SQL语句
	 * @param limitObj 分页参数对象，包含pagenum和pagesize属性
	 * @return 添加了LIMIT后的SQL语句
	 */
	public static String appendLimit(String sql, JSONObject limitObj) {
		// 如果分页参数为空，直接返回原SQL
		if (limitObj == null || limitObj.isEmpty()) {
			return sql;
		}

		// 获取页码
		int pageNum = limitObj.getInt("pagenum");
		// 获取每页大小
		int pageSize = limitObj.getInt("pagesize");
		// 计算偏移量
		int offset = (pageNum - 1) * pageSize;

		// 拼接LIMIT子句
		return sql + " limit " + offset + ", " + pageSize;
	}

}
